/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package core;

import com.sun.lwuit.list.ListModel;
import datamodel.ParkingRegion;
import datamodel.Position;
import datamodel.Statistic;
import datamodel.StorageInformer;
import datastorage.PositionsExtraDataStorage;
import datastorage.PositionManagerStorage;
import java.util.Hashtable;
import java.util.Vector;
import network.Connection;
import network.PacketBuilder;
import network.packets.Packet;
import network.packets.TaxiParkingStatisticResponce;
import network.packets.TaxiParkingsLastChangeDateResponce;
import network.packets.TaxiParkingsResponce;

/**
 *
 * @author Kvest
 */
public class PositionManager 
{
    private static final int UNKNOWN_LAST_CHANGE = 0;
    
    private final Vector positions;
    private final Vector regions;
    private PositionManagerStorage storage;
    private PositionsExtraDataStorage positionsExtraDataStorage;
    private long lastChange;
    private long lastUpdate;
    private int UIDInf;
    
    //Коллбэк проверки наличия обновления стоянок
    private Runnable positionsChanged, statisticChanged;
    
    public PositionManager()
    {
        positions = new Vector();
        regions = new Vector();
        storage = new PositionManagerStorage();
        positionsExtraDataStorage = new PositionsExtraDataStorage();
        lastChange = UNKNOWN_LAST_CHANGE;
        lastUpdate = UNKNOWN_LAST_CHANGE;
        positionsChanged = null;
        statisticChanged = null;
        UIDInf = -1;
        
        load();
        
        registerNetworkNotifiers();
    }

    private final void load()
    {
        clear();
        
        synchronized(positions)
        {
            storage.load(positions);
        }
        
        //Заполняем список регионов
        fillRegionsList();
        
        //Сортируем в алфовитном порядке
        sortPositions();
        
        //Грузим время последнего обновления
        lastUpdate = positionsExtraDataStorage.getLastUpdate();
        UIDInf = positionsExtraDataStorage.getUID();
    }
    
    public void save()
    {
        synchronized(positions)
        {
            storage.save(positions);
        }
    }
    
    private void fillRegionsList()
    {
        synchronized(regions) 
        {
            synchronized(positions)
            {
                Position position;
                boolean exists;
                for (int i = 0; i < positions.size(); ++i)
                {
                    position = (Position)positions.elementAt(i);
                    exists = false;
                    for (int j = 0; j < regions.size(); ++j)
                    {
                        if (((ParkingRegion)regions.elementAt(j)).getName().equals(position.getParkingRegion()))
                        {
                            ((ParkingRegion)regions.elementAt(j)).addCount(position.getCarsCountInt());
                            exists = true;
                            break;
                        }
                    }
                    if (!exists)
                    {
                        ParkingRegion region = new ParkingRegion(position.getParkingRegion());
                        region.setCount(position.getCarsCountInt());
                        regions.addElement(region);
                    }
                }
            }
        }
    }
    
    public void clear()
    {
        synchronized(positions)
        {
            positions.removeAllElements();
        }
        synchronized(regions)
        {
            regions.removeAllElements();
        }
    }
    
    public void addPosition(Position value)
    {
        synchronized(positions)
        {
            positions.addElement(value);
        }
        
        synchronized(regions)
        {
            boolean exists = false;
            for (int i = 0; i < regions.size(); ++i)
            {
                if (((ParkingRegion)regions.elementAt(i)).getName().equals(value.getParkingRegion()))
                {
                    exists = true;
                    break;
                }
            }
            if (!exists)
            {
                regions.addElement(new ParkingRegion(value.getParkingRegion()));
            }
        }
    }
    
    public void fillRegionsListModel(ListModel model)
    {
        synchronized(regions)
        {
            for (int i = 0; i < regions.size(); ++i)
            {
                model.addItem(regions.elementAt(i));
            }
        }
    }
    
    public void fillPositionsListModel(ListModel model)
    {
        synchronized(positions)
        {
            for (int i = 0; i < positions.size(); ++i)
            {
                model.addItem(positions.elementAt(i));
            }
        }
    }

    public String getNameByID(int id)
    {
        synchronized(positions)
        {
            for (int i = 0; i < positions.size(); ++i)
            {
                if (((Position)positions.elementAt(i)).getId() == id)
                {
                    return ((Position)positions.elementAt(i)).getParkingName();
                }
            }
        }

        return "";
    }

    public void updateCarsCount(Vector params)
    {
        Hashtable counts = new Hashtable(params.size()); 
        synchronized(positions)
        {
            //Обнуляем значения стоянок
            for (int i = 0; i < positions.size(); i++)
            {
                ((Position)positions.elementAt(i)).setCarsCount(0);
                ((Position)positions.elementAt(i)).setQueue("");
            }

            //Изменяем значения кол-ва машин по стоянкам
            Statistic statistic;
            String regionName;
            for (int i = 0; i < params.size(); ++i)
            {
                statistic = (Statistic)params.elementAt(i);
                //Изменяем значение кол-ва машин по стоянкам
                for (int j = 0; j < positions.size(); j++)
                if (((Position)positions.elementAt(j)).getId() == statistic.getId())
                {
                    ((Position)positions.elementAt(j)).setCarsCount(statistic.getCount());
                    ((Position)positions.elementAt(j)).setQueue(statistic.getQueue());
                    
                    regionName = ((Position)positions.elementAt(j)).getParkingRegion();
                    if (counts.contains(regionName))
                    {
                        counts.put(regionName, new Integer(statistic.getCount() + ((Integer)counts.get(regionName)).intValue()));
                    }
                    else
                    {
                        counts.put(regionName, new Integer(statistic.getCount()));
                    }
                    
                    break;
                }
            }
        }
        
        //Обновляем статистику по регионам
        synchronized(regions)
        {
            Integer count;
            for (int i = 0; i < regions.size(); ++i)
            { 
                if (counts.contains(((ParkingRegion)regions.elementAt(i)).getName()))
                {
                    count = (Integer)counts.get(((ParkingRegion)regions.elementAt(i)).getName());
                    ((ParkingRegion)regions.elementAt(i)).setCount(count.intValue());
                }
                else
                {
                    ((ParkingRegion)regions.elementAt(i)).setCount(0); 
                }
            }
        }
        
        counts = null;
    }
    
    public void deleteAll()
    {
        //Удалям все из памяти
        clear();
        
        //Удаляем все с RMS
        storage.clear();
        
        //обнуляем дату загруженных стоянок
        setLastUpdate(0);
    }

    public int getUIDInf() 
    {
        return UIDInf;
    }

    public void setUIDInf(int UIDInf) 
    {
        this.UIDInf = UIDInf;
        positionsExtraDataStorage.setUID(this.UIDInf);
    }
    
    
    
    public void setLastUpdate(long value)
    {
        lastUpdate = value;
        positionsExtraDataStorage.setLastUpdate(lastUpdate);
    }
    
    public void sortPositions()
    {
        synchronized(positions)
        {
            Position[] positionsTmp = new Position[positions.size()];
            positions.copyInto(positionsTmp);
            positions.removeAllElements();
            
            int minID;
            int count  = positionsTmp.length;
            while(true)
            {
                minID = -1;
                for (int i = 0; i < count; ++i)
                {
                    if (positionsTmp[i] != null)
                    {
                        if (minID == -1)
                        {
                            minID = i;
                        }
                        else if (positionsTmp[i].getParkingName().compareTo(positionsTmp[minID].getParkingName()) < 0)
                        {
                            minID = i;
                        }
                    }
                }
                
                if (minID != -1)
                {
                    positions.addElement(positionsTmp[minID]);
                    positionsTmp[minID] = null;
                }
                else
                {
                    break;
                }
            }

            positionsTmp = null;
        }
    }
    
    public void checkForPositionUpdates(Runnable positionsChanged, Runnable statisticChanged)
    {
        this.positionsChanged = positionsChanged;
        this.statisticChanged = statisticChanged;
        
        checkForPositionUpdates();
    }
    
    public String getPositionsInfo()
    {
        String result = "";
        Position position;
        int carsCount;
        synchronized(positions)
        {
            //Обнуляем значения стоянок
            for (int i = 0; i < positions.size(); i++)
            {
                position = (Position)positions.elementAt(i);
                try
                {
                    carsCount = Integer.parseInt(position.getCarsCount());
                }
                catch(Exception ex)
                {
                    carsCount = 0;
                }
                if (carsCount > 0)
                {
                    result += position.getParkingName() + ": " + position.getCarsCount() + "\n";
                }
            }
        }
        
        return result;
    }
    
    public String getFullPositionsInfo()
    {
        String result = "";
        Position position;
        int carsCount;
        synchronized(positions)
        {
            //Обнуляем значения стоянок
            for (int i = 0; i < positions.size(); i++)
            {
                position = (Position)positions.elementAt(i);
                try
                {
                    carsCount = Integer.parseInt(position.getCarsCount());
                }
                catch(Exception ex)
                {
                    carsCount = 0;
                }
                if (carsCount > 0)
                {
                    result += position.getParkingName() + ": " + position.getQueue() + "\n";
                }
            }
        }
        
        return result;
    }
    
    private void checkForPositionUpdates()
    {
        if (lastChange == UNKNOWN_LAST_CHANGE)//Если дата последнего обновления не загружена - грузим
        {
            //Формируем и отправляем запрос
            RuntimeData runtimeData = IMAPMIDlet.getMidlet().getRuntimeData();
            byte[] body = PacketBuilder.createBodyGetTaxiParkingsLastChangeDate(runtimeData.getPeopleID());
            byte[] data = PacketBuilder.createSrvTransfereData(PacketBuilder.DEFAULT_CONNECTION_TYPE, runtimeData.getSrvID(), 
                                                               PacketBuilder.DEFAULT_DESTINATION_ID, runtimeData.getGUID(), true, body);
            Connection.getConnection().send(data);
        }
        else 
        {
            //Если нужно обновить стоянки
            if (lastUpdate < lastChange)
            {
                //Формируем и отправляем запрос
                RuntimeData runtimeData = IMAPMIDlet.getMidlet().getRuntimeData();
                byte[] body = PacketBuilder.createBodyGetTaxiParkings(runtimeData.getPeopleID());
                byte[] data = PacketBuilder.createSrvTransfereData(PacketBuilder.DEFAULT_CONNECTION_TYPE, runtimeData.getSrvID(), 
                                                               PacketBuilder.DEFAULT_DESTINATION_ID, runtimeData.getGUID(), true, body);
                Connection.getConnection().send(data);
            }
            else 
            {
                //Запрашиваем статистику по стоянкам
                getStatistic();
            }            
        }          
    }
    
    private void getStatistic()//Запрос количества водителей на стоянках
    {
        //Формируем и отправляем запрос
        RuntimeData runtimeData = IMAPMIDlet.getMidlet().getRuntimeData();
        byte[] body = PacketBuilder.createGetTaxiParkingStatistic(runtimeData.getPeopleID());
        byte[] data = PacketBuilder.createSrvTransfereData(PacketBuilder.DEFAULT_CONNECTION_TYPE, runtimeData.getSrvID(), 
                                                       PacketBuilder.DEFAULT_DESTINATION_ID, runtimeData.getGUID(), true, body);
        Connection.getConnection().send(data);
    }
    
    private void saveLoadedPositions(TaxiParkingsResponce response)
    {
        //Удаляем все стоянки
	deleteAll();
        
	//Добавляем новые позиции
	for (int i = 0;i < response.count(); ++i)
	{
            addPosition(response.getPosition(i));
	}

        //Сортируем стоянки
        sortPositions();
        
	//Сохраняем список позиций в rms
	save();
        
	//Сохраняем время последнего обновления
	setLastUpdate(response.getLastUpdate());
        
        //Уведомляем что стоянки изменены
        positionsChangedEvent();
        
        //Продолжаем проверку обновления
	checkForPositionUpdates();
    }
    
    private void statisticChangedEvent()
    {
        if (statisticChanged != null)
        {
            statisticChanged.run();
        }        
        statisticChanged = null;
    }
    
    private void positionsChangedEvent()
    {
        if (positionsChanged != null)
        {
            positionsChanged.run();
        }
        positionsChanged = null;
    }
    
    public StorageInformer getStorageMemoryInfo()
    {
        return storage;
    }
    
    private void registerNetworkNotifiers()
    {
        Connection.getConnection().setPacketListener(Packet.TAXI_PARKING_LAST_CHANGE_DATE_RESPONCE, new Connection.PacketNotifier()
        {
            public void incomingPacket(Packet packet) 
            {
                lastChange = ((TaxiParkingsLastChangeDateResponce)packet).getLastChange();
                
                //Продолжаем проверку обновления
                checkForPositionUpdates();
            } 
        });
         
        Connection.getConnection().setPacketListener(Packet.TAXI_PARKINGS_RESPONCE, new Connection.PacketNotifier()
        {
            public void incomingPacket(Packet packet) 
            {
                saveLoadedPositions((TaxiParkingsResponce)packet);
            } 
        });
        
        Connection.getConnection().setPacketListener(Packet.TAXI_PARKINGS_RESPONCE2, new Connection.PacketNotifier()
        {
            public void incomingPacket(Packet packet) 
            {
                saveLoadedPositions((TaxiParkingsResponce)packet);
            } 
        });
        
        Connection.getConnection().setPacketListener(Packet.TAXI_PARKING_STATISTIC_RESPONCE, new Connection.PacketNotifier()
        {
            public void incomingPacket(Packet packet) 
            {
                //Обновляем количество машин на стоянке
                updateCarsCount(((TaxiParkingStatisticResponce)packet).getStatistics());
                        
                //Уведомляем что статистика изменена
                statisticChangedEvent();
            } 
        });
    }
}
